home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
TDE10SRC.ARJ
/
MAIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-05
|
26KB
|
842 lines
/******************* start of original comments ********************/
/*
* Written by Douglas Thomson (1989/1990)
*
* This source code is released into the public domain.
*/
/*
* Name: dte - Doug's Text Editor program - hardware dependent module
* Purpose: This file contains all the code that needs to be different on
* different hardware.
* File: hwibm.c
* Author: Douglas Thomson
* System: This particular version is for the IBM PC and close compatibles.
* It write directly to video RAM, so it is faster than other
* techniques, but will cause "snow" on most CGA cards. See the
* file "hwibmcga.c" for a version that avoids snow.
* The compiler is Turbo C 2.0, using one of the large data memory
* models.
* Date: October 10, 1989
* Notes: This module has been kept as small as possible, to facilitate
* porting between different systems.
*/
/********************* end of original comments ********************/
/*
* These routines were rewritten for Microsoft C. They are pretty much system
* dependent and pretty much Microsoft C dependent. I also renamed this file
* "main.c" - easier to find the main function.
*
* New editor name: tde, the Thomson-Davis Editor.
* Author: Frank Davis
* Date: June 5, 1991
*
* This modification of Douglas Thomson's code is released into the
* public domain, Frank Davis. You may distribute it freely.
*/
char *greatest_composer_ever = "W. A. Mozart, 1756-1791";
#include "tdestr.h" /* tde types */
#include "common.h"
#include "define.h"
#include "default.h"
#include "help.h"
#include "tdefunc.h"
#include "version.h" /* current version number */
#include <dos.h> /* for renaming files */
#ifdef __TURBOC__
#include <dir.h> /* for searching the current path */
#endif
#include <bios.h> /* for direct BIOS keyboard input */
#if defined( __TURBOC__ )
#include <alloc.h> /* for memory allocation */
#elif defined( __MSC__ )
#include <malloc.h> /* for memory allocation */
#endif
#include <io.h> /* for file attribute code */
#include <fcntl.h> /* open flags */
#if defined( __MSC__ )
#include <bios.h>
#include <errno.h>
#include <sys\types.h> /* S_IWRITE etc */
#endif
#include <sys\stat.h> /* S_IWRITE etc */
#if defined( __MSC__ )
void (interrupt far *old_control_c)( void ); /* variable for old CNTL-C */
#endif
int full_screen_buffer[2000]; /* 25 lines * 80 columns = 2000 characters */
/* (make it an int for the attribute) */
/*
* original control-break checking flag
*/
static int s_cbrk;
/*
* Name: main
* Purpose: To do any system dependent command line argument processing,
* and then call the main editor function.
* Date: October 10, 1989
* Passed: argc: number of command line arguments
* argv: text of command line arguments
*/
void main( argc, argv )
int argc;
char *argv[];
{
#if defined( __MSC__ )
union REGS inregs, outregs;
#endif
/*
* trap control-break to make it harmless, and turn checking off
*/
#if defined( __MSC__ )
inregs.h.ah = 0x33;
inregs.h.al = 0;
intdos( &inregs, &outregs );
s_cbrk = outregs.h.dl;
old_control_c = _dos_getvect( 0x23 );
_dos_setvect( 0x23, harmless );
inregs.h.ah = 0x33;
inregs.h.al = 1;
inregs.h.dl = 0;
intdos( &inregs, &outregs );
#else
s_cbrk = getcbrk( );
ctrlbrk( harmless );
setcbrk( 0 );
#endif
editor( argc, argv );
}
/*
* Name: error
* Purpose: To report an error, and usually make the user type <ESC> before
* continuing.
* Date: June 5, 1991
* Passed: kind: an indication of how serious the error was:
* WARNING: error, but editor can continue after <ESC>
* FATAL: abort the editor!
* message: string to be printed
* Notes: Show dummy the message and ask for <ESC> if needed.
*/
void error( kind, line, message )
int kind, line;
char *message;
{
char buff[MAX_COLS+2]; /* somewhere to store error before printing */
int c; /* character entered by user to continue */
char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute */
/*
* tell the user what kind of an error it is
*/
switch (kind) {
case FATAL:
strcpy( buff, "Fatal error: " );
break;
case WARNING:
strcpy( buff, "Warning: " );
break;
}
/*
* prepare the error message itself
*/
strcat( buff, message );
/*
* tell the user how to continue editing if necessary
*/
if (kind == WARNING)
strcat( buff, ": type <ESC>" );
/*
* output the error message
*/
save_screen_line( 0, line, line_buff );
set_prompt( buff, line );
if (kind == FATAL) {
/*
* no point in making the user type <ESC>, since the program is
* about to abort anyway...
*/
terminate( );
exit( 1 );
} else {
/*
* If necessary, force the user to acknowledge the error by
* typing <ESC> (or ^U).
* This prevents any extra commands the user has entered from
* causing problems after an error may have made them inappropriate.
*/
c = (c=getch()) != 0 ? c : getch() | 0x100;
while (key_func[c].func != AbortCommand)
c = (c=getch()) != 0 ? c : getch() | 0x100;
}
restore_screen_line( 0, line, line_buff );
}
/*
* Name: harmless
* Purpose: To process control-break by ignoring it, so that the editor is
* not aborted.
* Date: June 5, 1991
*/
#if defined( __MSC__ )
int interrupt far harmless( void )
#else
static int harmless(void)
#endif
{
return( 1 ); /* ignore */
}
/*
* Name: hw_xygoto
* Purpose: To move the cursor to a new position on the screen.
* Date: October 10, 1989
* Passed: [g_display.line]: the required line
* [g_display.col]: the required column
*/
void hw_xygoto( )
{
#if defined( __MSC__ )
union REGS inregs, outregs;
inregs.h.ah = 2;
inregs.h.bh = 0;
inregs.h.dh = g_display.line;
inregs.h.dl = g_display.col;
int86( 0x10, &inregs, &outregs );
#else
gotoxy( g_display.col+1, g_display.line+1 );
#endif
}
/*
* Name: hw_terminate
* Purpose: To restore the terminal to a safe state prior to leaving the
* editor.
* Date: October 10, 1989
*/
void hw_terminate( )
{
#if defined( __MSC__ )
union REGS inregs, outregs;
#endif
force_blank( );
#if defined( __MSC__ )
g_display.line = 0;
g_display.col = 0;
hw_xygoto( );
#else
gotoxy( g_display.ncols, g_display.nlines );
textattr( g_display.normal );
#endif
putch( ' ' );
printf( "tde version %s for IBM PC", VERSION );
/*
* restore control-break checking
*/
#if defined( __MSC__ )
_dos_setvect( 0x23, old_control_c );
inregs.h.ah = 0x33;
inregs.h.al = 1;
inregs.h.dl = s_cbrk;
intdos( &inregs, &outregs );
#else
setcbrk( s_cbrk );
#endif
}
/*
* Name: hw_initialize
* Purpose: To initialize the display ready for editor use.
* Date: June 5, 1991
*/
void hw_initialize( )
{
#if defined( __MSC__ )
struct vcfg cfg;
#else
struct text_info buff; /* for discovering display type */
#endif
unsigned paragraphs;
long space; /* amount of memory to use */
/*
* set up screen size
*/
g_display.ncols = MAX_COLS;
g_display.nlines = MAX_LINES - 1;
g_display.mode_line = MAX_LINES;
g_display.line_length = MAX_LINE_LENGTH;
/*
* work out what kind of display is in use, and set attributes and
* display address accordingly. Note that this will only work with
* close IBM compatibles.
*/
video_config( &cfg );
g_display.display_address = (char far *)cfg.videomem;
if (cfg.color == FALSE) {
g_display.head_color = HERC_REVERSE;
g_display.text_color = HERC_NORMAL;
g_display.mode_color = HERC_REVERSE;
g_display.block_color = HERC_REVERSE;
g_display.message_color = HERC_HIGH;
g_display.help_color = HERC_NORMAL;
} else {
if (cfg.mode == MONO_80) {
g_display.head_color = LCD_REVERSE;
g_display.text_color = LCD_NORMAL;
g_display.mode_color = LCD_REVERSE;
g_display.block_color = LCD_HIGH;
g_display.message_color = LCD_HIGH;
g_display.help_color = LCD_HIGH;
} else {
g_display.head_color = COLOR_HEAD;
g_display.text_color = COLOR_TEXT;
g_display.mode_color = COLOR_MODE;
g_display.block_color = COLOR_BLOCK;
g_display.message_color = COLOR_MESSAGE;
g_display.help_color = COLOR_HELP;
}
}
/*
* all the available memory for the text buffer
*/
#if defined( __MSC__ )
_dos_allocmem( 0xffff, ¶graphs );
space = paragraphs;
space = space << 4;
/*
* if using Microsoft C, allocate all available memory.
*/
/* if (space > 7000l)
space = 7000l; */
if (space <= 0)
return;
#else
space = farcoreleft() - 30000L;
#endif
#if defined( __MSC__ )
if ((g_status.start_mem = (text_ptr)halloc( space, sizeof( char ))) == NULL)
error( FATAL, g_display.nlines, "out of memory???" );
#else
if ((g_status.start_mem = farmalloc(space)) == NULL)
error( FATAL, g_display.nlines, "out of memory???" );
#endif
g_status.max_mem = addltop( space, g_status.start_mem );
}
/*
* Video BIOS Data Areas
* The BIOS routines maintain several dynamic variables in an area of
* memory called the Video Display Data Area. The following contains a
* summary of these variables' addresses, their symbolic names, and
* their contents. All addresses are relative to the 0x0000h segment.
*
* Address Name Type Description
* 0x0449 CRT_MODE Byte Current BIOS video number
* 0x044a CRT_COLS Word Number of displayed character columns
* 0x044c CRT_LEN Word Size of video buffer in bytes
* 0x044e CRT_START Word Offset of start of video buffer
* 0x0450 CURSOR_POSN Word Array of eight words containing the cursor
* position for each of eight possible
* video pages. The high-order byte of
* each word contains the character row,
* the low-order byte the character column
* 0x0460 CURSOR_MODE Word Starting and ending lines for alphanumeric
* cursor. The high-order byte contains
* the starting (top) line; the low-order
* byte contains the ending (bottom) line
* 0x0462 ACTIVE_PAGE Byte Currently displayed video page number
* 0x0463 ADDR_6845 Word I/O port address of CRT Controller's
* Address register (3B4h for mono;
* 3D4h for color)
* 0x0465 CRT_MODE_SET Byte Current value for Mode Control register
* (3B8h on MDA, 3D8h on CGA). On the
* EGA and VGA, the value emulates those
* used on the MDA and CGA.
* 0x0466 CRT_PALETTE Byte Current value for the CGA Color Select
* register (3D9h). On the EGA and VGA,
* the value emulates those used on the
* MDA and CGA.
* 0x0484 ROWS Byte Number of displayed character rows - 1
* 0x0485 POINTS Word Height of character matrix
* 0x0487 INFO Byte EGA and VGA display data
* 0x0488 INFO_3 Byte Configuration switches for EGA and VGA
* 0x0489 flags Byte Miscellaneous flags
* 0x048A DCC Byte Display Combination Code
* 0x04A8 SAVE_PTR Dword Pointer to BIOS save area
*
*/
void video_config( struct vcfg *cfg )
{
#pragma pack( 1 ) /* Use pragma to force packing on byte boundaries. */
struct LOWMEMVID
{
char vidmode; /* 0x449 */
unsigned scrwid; /* 0x44A */
unsigned scrlen; /* 0x44C */
unsigned scroff; /* 0x44E */
struct LOCATE
{
unsigned char col;
unsigned char row;
} csrpos[8]; /* 0x450 */
struct CURSIZE
{
unsigned char end;
unsigned char start;
} csrsize; /* 0x460 */
char page; /* 0x462 */
unsigned addr_6845; /* 0x463 */
char crt_mode_set; /* 0x465 */
char crt_palette[30]; /* 0x466 */
char rows; /* 0x484 */
unsigned points; /* 0x485 */
char ega_info; /* 0x487 */
char info_3; /* 0x488 */
} vid;
struct LOWMEMVID _far *pvid = &vid;
#pragma pack( ) /* revert to previously defined pack pragma. */
union REGS in, out;
/* Move system information into uninitialized structure variable. */
movedata( 0, 0x449, FP_SEG( pvid ), FP_OFF( pvid ), sizeof( vid ) );
in.h.ah = 0x12;
in.h.bl = 0x10;
int86( VIDEO_INT, &in, &out );
if (out.h.bl == 0x10) { /* EGA */
if (vid.addr_6845 == 0x3D4)
cfg->rescan = TRUE;
else
cfg->rescan = FALSE;
} else {
if ((vid.ega_info & 0x08) && (vid.addr_6845 == 0x3D4))
cfg->rescan = TRUE;
else
cfg->rescan = FALSE;
}
cfg->mode = vid.vidmode;
if (vid.addr_6845 == 0x3D4) {
cfg->color = TRUE;
FP_SEG( cfg->videomem ) = 0xb800;
} else {
cfg->color = FALSE;
FP_SEG( cfg->videomem ) = 0xb000;
}
FP_OFF( cfg->videomem ) = 0x0000;
}
/*
* Name: hw_move
* Purpose: To move data from one place to another as efficiently as
* possible.
* Date: October 10, 1989
* Passed: dest: where to copy to
* source: where to copy from
* number: number of bytes to copy
* Notes: moves may be (usually will be) overlapped. Although we can
* move up to 64k-1 bytes at once, unfortunately we can safely
* move only 16k bytes at one time. The pointer checking functions
* ensure that a pointer is not within 16k of a segment.
*/
void hw_move( dest, source, number )
text_ptr dest;
text_ptr source;
long number;
{
unsigned long s, d;
s = ptoul( source );
d = ptoul( dest );
if (number < 0)
/*
* this should never happen...
*/
error( WARNING, g_display.nlines, "negative move - contact Frank Davis" );
else if (s == d)
/*
* nothing to be done
*/
;
else if (s > d) {
while (number > 0x4000L) {
dest = cpf( dest );
source = cpf( source );
memmove( (char *)dest, (char *)source, 0x4000 );
number -= 0x4000L;
dest = addltop( 0x4000L, dest );
source = addltop( 0x4000L, source );
}
/*
* now less than 16K is left, so finish off the move
*/
dest = cpf( dest );
source = cpf( source );
memmove( (char *)dest, (char *)source, (unsigned)number );
} else {
source = addltop( number, source );
dest = addltop( number, dest );
while (number > 0x4000L) {
dest = cpb( dest );
source = cpb( source );
source = addltop( -0x4000L, source );
dest = addltop( -0x4000L, dest );
number -= 0x4000L;
memmove( (char *)dest, (char *)source, 0x4000 );
}
source = cpb( source );
dest = cpb( dest );
source = addltop( -number, source );
dest = addltop( -number, dest );
memmove( (char *)dest, (char *)source, (unsigned)number );
}
}
/*
* Name: hw_fattrib
* Purpose: To determine the current file attributes.
* Date: October 17, 1989
* Passed: name: name of file to be checked
* Returns: current read/write/execute etc attributes of the file, or
* ERROR if file did not exist etc.
*/
int hw_fattrib( name )
char *name;
{
int rc;
#if defined( __MSC__ )
rc = access( name, EXIST );
#else
rc = _chmod( name, EXIST );
#endif
return( rc );
}
/*
* Name: hw_unlink
* Purpose: To delete a file, regardless of access modes.
* Date: October 17, 1989
* Passed: name: name of file to be removed
* Returns: OK if file could be removed
* ERROR otherwise
*/
int hw_unlink( name, line )
char *name;
int line;
{
int result;
int rc;
char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute */
rc = OK;
#if defined( __MSC__ )
if ((result = access( name, EXIST )) != -1 && errno != EACCES) {
#else
if ((result = _chmod( name, EXIST )) != -1 && (result & FA_RDONLY) != 0) {
#endif
/*
* file cannot be written
*/
save_screen_line( 0, line, line_buff );
set_prompt( "File is write protected! Overwrite anyway? (y/n): ", line );
if (get_yn( ) != A_YES)
rc = ERROR;
#if defined( __MSC__ )
if (rc == OK && chmod( name, S_IWRITE ) == ERROR)
rc = ERROR;
#else
if (rc == OK && _chmod( name, 1, 0 ) == ERROR)
rc = ERROR;
#endif
restore_screen_line( 0, line, line_buff );
}
if (rc == OK)
rc = unlink( name );
return( rc );
}
/*
* Name: write_file
* Purpose: To write text to a file, eliminating trailing space on the
* way.
* Date: June 5, 1991
* Passed: name: name of disk file or device
* mode: fopen flags to be used in open
* start: first character in text buffer
* end: last character (+1) in text buffer
* block: write a file or a marked block
* prompt_line: line to display error messages
* Returns: OK, or ERROR if anything went wrong
*/
int write_file( name, mode, start, end, block, prompt_line )
char *name;
char *mode;
text_ptr start;
text_ptr end;
int block, prompt_line;
{
FILE *fp; /* file to be written */
int rc;
char *p, *q;
int len;
int bc, ec, last_c;
file_infos *file;
rc = OK;
if ((fp = fopen( name, mode )) == NULL)
rc = ERROR;
else {
/*
* save the file, eliminating trailing space
*/
start = cpf( start );
if (block == LINE || block == BLOCK) {
if (g_status.marked_file == NULL)
rc = ERROR;
else if (block == BLOCK) {
file = g_status.marked_file;
bc = file->block_bc;
ec = file->block_ec;
last_c = ec + 1 - bc;
}
}
p = g_status.line_buff;
if (rc == OK) {
for (;ptoul( start ) < ptoul( end );) {
if (block == NOTMARKED || block == LINE) {
copy_line( start, prompt_line );
len = linelen( start );
if (*(p+len) == CONTROL_Z) {
*(p+len) = '\n';
*(p+len+1) = CONTROL_Z;
}
} else {
load_buff( p, start, bc, ec, BLOCK );
*(p+last_c) = '\n';
*(p+last_c+1) = CONTROL_Z;
len = last_c;
}
for (q=p+len-1; len > 0; len--, q--) {
if (*q == ' ') {
*q = '\n';
*(q+1) = CONTROL_Z;
} else
break;
}
len = find_CONTROL_Z( p );
fwrite( p, sizeof( char ), len, fp );
start = find_next( start );
if (start == NULL)
start = end;
}
rc = fclose( fp );
}
}
return( rc );
}
/*
* Name: hw_save
* Purpose: To save text to a file, eliminating trailing space on the
* way.
* Date: November 11, 1989
* Passed: name: name of disk file
* start: first character in text buffer
* end: last character (+1) in text buffer
* Returns: OK, or ERROR if anything went wrong
* Notes: Trailing space at the very end of the file is NOT removed,
* so that a block write of a block of spaces will work.
* No error messages are displayed here, so the caller must
* both tell the user what is happening, and print an error
* message if anything goes wrong.
* This function is in the hardware dependent module because
* some computers require non-standard open parameters...
*/
int hw_save( name, start, end, block, prompt_line )
char *name;
text_ptr start;
text_ptr end;
int block, prompt_line;
{
return write_file( name, "w", start, end, block, prompt_line );
}
/*
* Name: hw_append
* Purpose: To append text to a file.
* Date: November 11, 1989
* Passed: name: name of disk file
* start: first character in text buffer
* end: last character (+1) in text buffer
* Returns: OK, or ERROR if anything went wrong
* Notes: No error messages are displayed here, so the caller must
* both tell the user what is happening, and print an error
* message if anything goes wrong.
* This function is in the hardware dependent module because
* some computers require non-standard open parameters...
*/
int hw_append( name, start, end, block, prompt_line )
char *name;
text_ptr start;
text_ptr end;
int block, prompt_line;
{
return write_file( name, "a", start, end, block, prompt_line );
}
/*
* Name: hw_print
* Purpose: To print text to a printer.
* Date: November 11, 1989
* Passed: start: first character in text buffer
* end: last character (+1) in text buffer
* Returns: OK, or ERROR if anything went wrong
* Notes: This function is in the hardware dependent module because
* some computers require non-standard open parameters...
*/
int hw_print( start, end, block, prompt_line )
text_ptr start;
text_ptr end;
int block, prompt_line;
{
return write_file( "PRN", "a", start, end, block, prompt_line );
}
/*
* Name: hw_load
* Purpose: To load a file into the text buffer.
* Date: November 11, 1989
* Passed: name: name of disk file
* start: first character in text buffer
* limit: last available character in text buffer
* end: last character of file in text buffer
* Returns: OK, or ERROR if anything went wrong
* Notes: All error messages are displayed here, so the caller should
* neither tell the user what is happening, nor print an error
* message if anything goes wrong.
* This function is in the hardware dependent module because
* some computers require non-standard open parameters...
*/
int hw_load( name, start, limit, end, line )
char *name;
text_ptr start;
text_ptr limit;
text_ptr *end;
int line;
{
int fd; /* file being read */
int length; /* number of bytes actually read */
int rc;
char buff[MAX_COLS+2];
/*
* try reading the file
*/
rc = OK;
if ((fd = open( name, O_RDONLY )) == ERROR) {
combine_strings( buff, "File '", name, "'not found" );
error( WARNING, line, buff );
rc = ERROR;
} else {
/*
* read the entire file, without going past end of buffer.
* Note that this means a file that is within 1K of the limit
* will not be accepted. length set to a number > 0 for first loop
*/
limit = addltop( -1024, limit );
start = cpf( start );
for (length=1; rc != ERROR && length > 0;) {
if (ptoul( start ) >= ptoul( limit )) {
combine_strings( buff, "file '", name, "'too big" );
error( WARNING, line, buff );
rc = ERROR;
} else {
if ((length = read( fd, (char *)start, 1024 )) == ERROR) {
combine_strings( buff, "error reading file '", name, "'" );
error( WARNING, line, buff );
rc = ERROR;
} else
start = addltop( length, start );
start = cpf( start );
}
}
/*
* close the file and report the final character in the buffer
*/
close( fd );
*end = start;
}
return( rc );
}
/*
* Name: get_help
* Purpose: save the screen and display key definitions
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
*/
void get_help( window )
windows *window;
{
char *help;
int line;
xygoto( -1, -1 );
memcpy( full_screen_buffer, g_display.display_address, 4000 );
help = help_screen[0];
for (line=0; help != NULL; ) {
s_output( help, line, 0, g_display.help_color );
help = help_screen[++line];
}
line = (line = getch()) != 0 ? 0 : getch();
memcpy( g_display.display_address, full_screen_buffer, 4000 );
}
/*
* Name: show_credits
* Purpose: display authors
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
*/
void show_credits( )
{
char *credit;
int line;
xygoto( -1, -1 );
credit = credit_screen[0];
for (line=0; credit != NULL; ) {
s_output( credit, line+2, 11, g_display.text_color );
credit = credit_screen[++line];
}
}